package com.untour.im.codec.protocol.packet.codec;

import com.alibaba.fastjson2.TypeReference;
import com.untour.im.codec.constants.IMConstants;
import com.untour.im.codec.protocol.command.Command;
import com.untour.im.codec.protocol.message.body.MessageBody;
import com.untour.im.codec.protocol.packet.request.PacketData;
import com.untour.im.codec.protocol.packet.request.body.HeartBeatRequestPacketData;
import com.untour.im.codec.protocol.packet.request.body.LoginRequestPacketData;
import com.untour.im.codec.protocol.packet.request.body.MessageRequestPacketData;
import com.untour.im.codec.protocol.packet.request.body.SeqIdRequestPacketData;
import com.untour.im.codec.protocol.packet.request.header.RequestPacketHeader;
import com.untour.im.codec.protocol.serialize.Serializer;
import com.untour.im.codec.protocol.serialize.json.JSONSerializer;
import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * @description: 将ByteBuf转化为Message实体，根据私有协议转换
 * 私有协议规则，
 * 4位表示Command表示消息的开始，
 * 4位表示version
 * 4位表示clientType
 * 4位表示messageType
 * 4位表示appId
 * 4位表示imei长度
 * 4位表示数据长度
 * imei
 * data
 */
@Slf4j
public class RequestPacketCodec {
    public static final RequestPacketCodec INSTANCE = new RequestPacketCodec();

    private final Map<Byte, Serializer> serializerMap;
    private final Map<Byte, TypeReference<? extends MessageBody>> packetTypeMap;


    private RequestPacketCodec(){
        // 指令 和 对应的数据包类 映射
        packetTypeMap = new HashMap<>();
        packetTypeMap.put(Command.LOGIN, IMConstants.LOGIN_MESSAGE_TYPE_REFERENCE);
        packetTypeMap.put(Command.HEARTBEAT_REQUEST, IMConstants.HEART_BEAT_MESSAGE_TYPE_REFERENCE);
        packetTypeMap.put(Command.SINGLE_MESSAGE_REQUEST, IMConstants.SINGLE_TXT_MESSAGE_TYPE_REFERENCE);
        packetTypeMap.put(Command.GROUP_MESSAGE_REQUEST, IMConstants.GROUP_TXT_MESSAGE_TYPE_REFERENCE);

        // 序列化协议ID 和 协议实现类 映射
        serializerMap = new HashMap<>();
        Serializer serializer = new JSONSerializer();
        serializerMap.put(serializer.getSerializerAlgorithm(), serializer);
    }

    private Serializer getSerializer(byte serializerType) {
        return serializerMap.get(serializerType);
    }

    private TypeReference<? extends MessageBody> getRequestType(byte command) {
        return packetTypeMap.get(command);
    }

    public PacketData<RequestPacketHeader,MessageBody> decode(ByteBuf byteBuf) {

        /** 获取command*/
        byte command = byteBuf.readByte();

        /** 获取version*/
        int version = byteBuf.readInt();

        /** 获取clientType*/
        int clientType = byteBuf.readInt();

        /** 获取serializerType*/
        byte serializerType = byteBuf.readByte();

        /** 获取appId*/
        int appId = byteBuf.readInt();

        /** 获取imeiLength*/
        int imeiLength = byteBuf.readInt();

        /** 获取bodyLen*/
        int bodyLen = byteBuf.readInt();

        //判断数据长度完整
        if (byteBuf.readableBytes() < bodyLen + imeiLength) {
            byteBuf.resetReaderIndex();
            return null;
        }

        //读取imei
        byte[] imeiData = new byte[imeiLength];
        byteBuf.readBytes(imeiData);
        String imei = new String(imeiData);

        PacketData message;
         if(command == Command.ID_REQUEST){
            message = new SeqIdRequestPacketData();
        } else if(command == Command.LOGIN){
            message = new LoginRequestPacketData();
        } else if(command == Command.HEARTBEAT_REQUEST){
            message = new HeartBeatRequestPacketData();
        } else {
            message = new MessageRequestPacketData();
        }
        RequestPacketHeader requestPacketHeader = new RequestPacketHeader();
        requestPacketHeader.setAppId(appId);
        requestPacketHeader.setClientType(clientType);
        requestPacketHeader.setCommand(command);
        requestPacketHeader.setImeiLength(imeiLength);
        requestPacketHeader.setLength(bodyLen);
        requestPacketHeader.setVersion(version);
        requestPacketHeader.setMessageType(serializerType);
        requestPacketHeader.setImei(imei);
        message.setHeader(requestPacketHeader);

        //获取序列化类型
        Serializer serializer = this.getSerializer(serializerType);
        TypeReference<? extends MessageBody> requestType = this.getRequestType(command);
        //读取内容
        byte[] bodyData = new byte[bodyLen];
        byteBuf.readBytes(bodyData);

        if (serializer != null) {
            message.setMessageBody(serializer.deserialize(requestType, bodyData));
        } else {
            log.warn("无法解析包数据");
            message = null;
        }
        byteBuf.markReaderIndex();
        return message;
    }
}
